package org.statewalker.parser.wiki.tokenizer;

import org.statewalker.parser.wiki.grammar.WikiBlockGrammar;
import org.statewalker.parser.wiki.tokenizer.base.StreamToken;
import org.statewalker.parser.wiki.tokenizer.block.HeaderTokenizer;
import org.statewalker.parser.wiki.tokenizer.block.HorlineTokenizer;
import org.statewalker.parser.wiki.tokenizer.block.ListTokenizer;
import org.statewalker.parser.wiki.tokenizer.block.ParagraphTokenizer;
import org.statewalker.parser.wiki.tokenizer.block.TableTokenizer;
import org.statewalker.tokenizer.base.NewLineTokenizer;
import org.statewalker.tokenizer.stream.ICharStream;
import org.statewalker.tokenizer.stream.ICharStream.IMarker;
import org.statewalker.tokenizer.stream.ICharStream.Pointer;

public class BlockTokenizer extends CompositeStreamTokenizer {

    private NewLineTokenizer<StreamToken> fNewLineTokenizer;

    public BlockTokenizer(
        NewLineTokenizer<StreamToken> newLineTokenizer,
        WikiBlockGrammar wikiGrammar) {
        fNewLineTokenizer = newLineTokenizer;
        addTokenizer(new HorlineTokenizer(getFactory(wikiGrammar.S_HR)));
        addTokenizer(new ListTokenizer(getFactory(wikiGrammar.S_LI)));
        addTokenizer(new HeaderTokenizer(getFactory(wikiGrammar.S_H1)));
        addTokenizer(new TableTokenizer(getFactory(wikiGrammar.S_TD)));
        addTokenizer(new ParagraphTokenizer(
            getFactory(wikiGrammar.S_P),
            fNewLineTokenizer));
    }

    @Override
    public StreamToken read(ICharStream stream) {
        IMarker marker = stream.markPosition();
        StreamToken result = null;
        try {
            StreamToken lines = null;
            Pointer ptr = marker.getPointer();
            if (ptr.pos == 0
                || (lines = fNewLineTokenizer.read(stream)) != null) {
                StreamToken token = super.read(stream);
                if (token != null) {
                    // TODO: prepend lines to the token
                    result = lines;
                    result = token;
                }
            }
            return result;
        } finally {
            marker.close(result == null);
        }
    }
}
